﻿/*----------------------------------------------------------------
//  <copyright file="YfxytSmsSender.cs" company="MicroCloud@151504200868">
//      Copyright © 2020-2024 MicroCloud Corporation, All rights reserved.
//  </copyright>
//  <site>https://gitee.com/chenmm123/microclouds</site>
//  <last-editor>cmm</last-editor>
//  <last-date>2024-03-04 14:53</last-date>
//----------------------------------------------------------------*/

namespace MicroCloud.SMS.Sender
{
    #region "逸峰信盈通短信发送者"
    /// <summary>
    /// 逸峰信盈通短信发送者
    /// </summary>
    public class YfxytSmsSender : ISmsSender
    {
        #region 属性
        #region "获取 服务提供者对象"
        /// <summary>
        /// 获取 服务提供者对象
        /// </summary>
        protected IServiceProvider ServiceProvider { get; }
        #endregion
        #region "获取 事件总线"
        /// <summary>
        /// 获取 事件总线
        /// </summary>
        protected IEventBus EventBus => ServiceProvider.GetService<IEventBus>();
        #endregion
        #region "获取 日志对象"
        /// <summary>
        /// 获取 日志对象
        /// </summary>
        protected ILogger Logger { get; }
        #endregion
        #region "获取 短信配置选项"
        /// <summary>
        /// 获取 短信配置选项
        /// </summary>
        protected SmsOptions SmsOpt => ServiceProvider.GetService<IConfiguration>()?.GetSmsOptions();
        #endregion

        #region "获取 HttpClient工厂对象"
        /// <summary>
        /// 获取 HttpClient工厂对象
        /// </summary>
        protected IHttpClientFactory HttpClientFactory => ServiceProvider.GetService<IHttpClientFactory>();
        #endregion

        #region "获取 短信查询功能"
        /// <summary>
        /// 获取 短信查询功能
        /// </summary>
        protected ISmsInquirer SmsInquirer => ServiceProvider.GetService<ISmsInquirer>();
        #endregion

        #endregion

        #region "构造函数"
        #region "初始化一个逸峰信盈通短信发送者的新实例"
        /// <summary>
        /// 初始化一个逸峰信盈通短信发送者 <see cref="YfxytSmsSender"/> 的新实例
        /// </summary>
        /// <param name="provider">服务提供者</param>
        public YfxytSmsSender(IServiceProvider provider)
        {
            ServiceProvider = provider;
            Logger = provider.GetLogger(GetType());
        }
        #endregion

        #endregion

        #region "方法"
        #region "从配置文件中获取短信模板"
        /// <summary>
        /// 从配置文件中获取短信模板
        /// </summary>
        /// <param name="smsType">短信类型</param>
        /// <returns></returns>
        public virtual async Task<string> GetTemplateCodeAsync(SmsType smsType)
        {
            var templateCode = "";
            switch (smsType)
            {
                case SmsType.VerifyCode:
                    templateCode = SmsOpt.VerifyCodeTemplate;
                    break;
                case SmsType.Notice:
                    templateCode = SmsOpt.NoticeTemplate;
                    break;
                case SmsType.Promote:
                    templateCode = SmsOpt.PromoteTemplate;
                    break;
            }
            return await Task.Factory.StartNew(() => templateCode);
        }
        #endregion
        #region "发送短信"
        /// <summary>
        /// 发送短信
        /// </summary>
        /// <param name="paramsDto">短信发送参数DTO</param>
        /// <param name="phoneNumbers">接收短信的手机号码</param>
        /// <returns></returns>
        public virtual async Task<OperationResult<SendResponse>> SendAsync(SendParamsDto paramsDto, params string[] phoneNumbers)
        {
            var result = await SendByJnyfAsync(SmsOpt.RegionId, SmsOpt.Id, SmsOpt.Secret
                        , SmsOpt.Domain
                        , paramsDto.MsgContent
                        , paramsDto.UpExtendCode
                        , phoneNumbers);
            //触发发送成功事件
            if (result.Succeeded)
            {
                SmsSendEventData eventData = new()
                {
                    PhoneNumbers = phoneNumbers,
                    ParamsDto = paramsDto,
                    Response = result.Data,
                };
                await EventBus?.PublishAsync(this, eventData);
            }
            return await Task.Factory.StartNew(() => result);
        }
        #endregion
        #region "批量发送短信"
        /// <summary>
        /// 批量发送短信
        /// </summary>
        /// <param name="paramsDto">短信批量发送参数DTO</param>
        /// <returns></returns>
        public virtual async Task<OperationResult<SendResponse>> SendBatchAsync(BatchSendParamsDto paramsDto)
        {
            var result = await SendBatchByJnyfAsync(SmsOpt.RegionId, SmsOpt.Id, SmsOpt.Secret
                        , SmsOpt.Domain, paramsDto);
            //触发发送成功事件
            if (result.Succeeded)
            {
                SmsBatchSendEventData eventData = new()
                {
                    ParamsDto = paramsDto,
                    Response = result.Data,
                };
                await EventBus?.PublishAsync(this, eventData);
            }
            return await Task.Factory.StartNew(() => result);
        }
        #endregion

        #endregion

        #region "受保护方法"
        #region "以逸峰信盈通作为服务商发送短信"
        /// <summary>
        /// 以逸峰信盈通作为服务商发送短信
        /// </summary>
        /// <param name="regionId">区域ID</param>
        /// <param name="accessKeyId">API的密钥Id</param>
        /// <param name="accessKeySecret">API的密钥Secret</param>
        /// <param name="domain">产品域名</param>
        /// <param name="msgContent">短信内容</param>
        /// <param name="upExtendCode">上行短信扩展码，无特殊需要此字段的用户请忽略此字段。</param>
        /// <param name="phoneNumbers">接收短信的手机号码</param>
        /// <returns></returns>
        protected virtual async Task<OperationResult<SendResponse>> SendByJnyfAsync(string regionId, string accessKeyId, string accessKeySecret
            //, string Product <param name="Product">产品名称 Dysmsapi</param>
            , string domain
            , string msgContent
            , string upExtendCode
            , params string[] phoneNumbers
            )
        {
            regionId = regionId.IsMissing() ? JnyfConstants.RegionId : regionId;
            domain = domain.IsMissing() ? JnyfConstants.Domain : domain;

            Check.NotNullOrEmpty(accessKeyId, nameof(accessKeyId));
            Check.NotNullOrEmpty(accessKeySecret, nameof(accessKeySecret));

            if (phoneNumbers.Length < 1)
            {
                throw new Exception(I18N.T("手机号码不能为空"));
            }
            if (phoneNumbers.Length > 1000)
            {
                throw new Exception(I18N.T("手机号码数量不能超过 {0}", 1000));
            }
            var sendPhoneNumbers = phoneNumbers.Join(",");

            var request = new HttpRequestMessage(HttpMethod.Post,
            $"http://{domain}/{regionId}/{JnyfConstants.SendSmsAction}");
            var md5AccessKeySecret = accessKeySecret.ToMD5().ToLower();
            // var bodyData = $"{{\"phone\":\"{sendPhoneNumbers}\",\"message\":\"{MsgContent}\",\"acctno\":\"{AccessKeyId}\",\"password\":\"{md5AccessKeySecret}\",\"extno\":\"{UpExtendCode}\"}}";
            // var bodyData = $"phone={sendPhoneNumbers}&message={MsgContent}&acctno={AccessKeyId}&password={md5AccessKeySecret}&extno={UpExtendCode}";
            // 备注
            //"application/x-www-form-urlencoded";
            //MultipartFormDataContent =》multipart / form - data
            //FormUrlEncodedContent =》application / x - www - form - urlencoded
            //StringContent =》application / json等
            //StreamContent =》binary
            var nameValueCollection = new List<KeyValuePair<string, string>>
            {
                new KeyValuePair<string, string>("phone", sendPhoneNumbers),
                new KeyValuePair<string, string>("message", msgContent),
                new KeyValuePair<string, string>("acctno", accessKeyId),
                new KeyValuePair<string, string>("password", md5AccessKeySecret),
                new KeyValuePair<string, string>("extno", upExtendCode)
            };
            // request.Content = new JsonContent(bodyData);
            request.Content = new FormUrlEncodedContent(nameValueCollection);

            var client = HttpClientFactory.CreateClient();
            var response = await client.SendAsync(request);
            var responseContentStr = await response.Content.ReadAsStringAsync();

            var sendResponse = new SendResponse
            {
                RequestId = Guid.NewGuid().ToString()
            };

            if (!response.IsSuccessStatusCode)
            {
                sendResponse.Code = response.StatusCode.ToString();
                sendResponse.Message = responseContentStr;

                var result1 = OperationResult.Error(sendResponse);
                return await Task.Factory.StartNew(() => result1);
            }
            //处理XML返回结果
            try
            {
                XmlDocument xmldoc = new();
                xmldoc.LoadXml(responseContentStr);
                XmlNode xmlNodeReturnSms = xmldoc.SelectSingleNode("returnsms");
                if (xmlNodeReturnSms == null)
                {
                    sendResponse.Code = response.StatusCode.ToString();
                    sendResponse.Message = responseContentStr;

                    var result2 = OperationResult.Error(sendResponse);
                    return await Task.Factory.StartNew(() => result2);
                }
                //string returnstatus = xmlNodeReturnSms.Attributes["returnstatus"]?.Value;
                //string message = xmlNodeReturnSms.Attributes["message"]?.Value;
                //string taskID = xmlNodeReturnSms.Attributes["taskID"]?.Value;
                string returnstatus = xmlNodeReturnSms.SelectSingleNode("returnstatus")?.InnerText;
                string message = xmlNodeReturnSms.SelectSingleNode("message")?.InnerText;
                string taskID = xmlNodeReturnSms.SelectSingleNode("taskID")?.InnerText;

                // var returnSms = SerializeHelper.FromXml<returnsms>(clientResult);
                sendResponse.Code = message;
                sendResponse.Message = returnstatus;
                sendResponse.BizId = taskID;

                if (!sendResponse.Succeeded)
                {
                    var result3 = OperationResult.Error(sendResponse);
                    return await Task.Factory.StartNew(() => result3);
                }

                ////查询发送状态
                ////为保证服务商数据已持久化可供查询，建议线程睡眠3秒后继续执行下步操作
                //Thread.Sleep(3000);
                ////设置查询参数
                //SmsQueryParamsDto QueryParamsDto = new SmsQueryParamsDto
                //{
                //    PhoneNumber = "",
                //    SendDate = DateTime.Now,
                //    PageSize = 10,
                //    CurrentPage = 1,
                //    BizId = smsSentResponse.BizId,
                //};
                //var statusResponse = await SmsInquirer.QuerySentSmsStatusAsync(QueryParamsDto);
                //if (!statusResponse.Succeeded)
                //{
                //    var result4 = new OperationResult<SmsSentResponse>(statusResponse.ResultType, statusResponse.Message, smsSentResponse);
                //    return await Task.Factory.StartNew(() => result4);
                //}

                //smsSentResponse.SmsStatus.SmsStatusDtos = statusResponse.Data.SmsStatusDtos.FindAll(o => o.BizId == smsSentResponse.BizId);
                //smsSentResponse.SmsStatus.TotalCount = smsSentResponse.SmsStatus.SmsStatusDtos.Count.ToString();
                //var thisStatus = statusResponse.Data.SmsStatusDtos.FirstOrDefault(o => o.BizId == smsSentResponse.BizId);
                //if (thisStatus == null)
                //{
                //    //TODO:如果查询不到，默认发送成功，以规避部分手机号查询不到短信发送记录的问题。
                //    //var result5 = new OperationResult<SmsSentResponse>(OperationResultType.Error, "未查询到短信发送的状态信息", smsSentResponse);
                //    //return await Task.Factory.StartNew(() => result5);
                //    var result5 = new OperationResult<SmsSentResponse>(OperationResultType.Success, "短信发送成功", smsSentResponse);
                //    return await Task.Factory.StartNew(() => result5);
                //}
                //if (thisStatus.SendStatus == SmsSendStatus.Failed || thisStatus.ReceiveStatus == SmsReceiveStatus.Failed)
                //{
                //    smsSentResponse.Message = thisStatus.ErrCode.IsMissing() ? $"{thisStatus.Message}" : $"{thisStatus.Message}：{thisStatus.ErrCode}";
                //    var resul6 = new OperationResult<SmsSentResponse>(OperationResultType.Error, "短信发送失败", smsSentResponse);
                //    return await Task.Factory.StartNew(() => resul6);
                //}

                var result = OperationResult.Success(sendResponse);
                return await Task.Factory.StartNew(() => result);
            }
            catch
            {
                //smsSentResponse.Code = response.StatusCode.ToString();
                //smsSentResponse.Message = responseContentStr;
                sendResponse.Code = "ValidError";
                sendResponse.Message = I18N.T("调用接口返回错误，有可能参数设置不正确！");

                var result = OperationResult.Error(sendResponse);
                return await Task.Factory.StartNew(() => result);
            }
        }
        #endregion
        #region "以逸峰信盈通作为服务商批量发送短信"
        /// <summary>
        /// 以逸峰信盈通作为服务商批量发送短信
        /// </summary>
        /// <param name="regionId">区域ID</param>
        /// <param name="accessKeyId">密钥Id</param>
        /// <param name="accessKeySecret">密钥Secret</param>
        /// <param name="domain">产品域名</param>
        /// <param name="paramsDto">短信批量发送参数</param>
        /// <returns></returns>
        protected virtual async Task<OperationResult<SendResponse>> SendBatchByJnyfAsync(string regionId, string accessKeyId, string accessKeySecret
            , string domain
            , BatchSendParamsDto paramsDto
            )
        {
            regionId = regionId.IsMissing() ? JnyfConstants.RegionId : regionId;
            domain = domain.IsMissing() ? JnyfConstants.Domain : domain;

            Check.NotNullOrEmpty(accessKeyId, nameof(accessKeyId));
            Check.NotNullOrEmpty(accessKeySecret, nameof(accessKeySecret));

            var batchSendParamsLine = paramsDto?.Lines;
            if (paramsDto == null || batchSendParamsLine == null || batchSendParamsLine.Count < 1)
            {
                throw new Exception(I18N.T("参数不能为空"));
            }
            if (batchSendParamsLine.Exists(o => o.PhoneNumber.IsMissing()))
            {
                throw new Exception(I18N.T("手机号码不能为空"));
            }
            if (batchSendParamsLine.Exists(o => o.MsgContent.IsMissing()))
            {
                throw new Exception(I18N.T("短信内容不能为空"));
            }

            paramsDto.GetLineParamsJoinString(out string phoneNumberJoin
                , out string signNameJoin
                , out string templateParamJoin
                , out string msgContentJoin
                , out string smsUpExtendCodeJoin);
            //设置短息处理程序
            var request = new HttpRequestMessage(HttpMethod.Post,
            $"http://{domain}/{regionId}/{JnyfConstants.SendBatchSmsAction}");
            var md5AccessKeySecret = accessKeySecret.ToMD5().ToLower();
            // var bodyData = $"{{\"phone\":\"{sendPhoneNumbers}\",\"message\":\"{MsgContent}\",\"acctno\":\"{AccessKeyId}\",\"password\":\"{md5AccessKeySecret}\",\"extno\":\"{UpExtendCode}\"}}";
            // var bodyData = $"phone={sendPhoneNumbers}&message={MsgContent}&acctno={AccessKeyId}&password={md5AccessKeySecret}&extno={UpExtendCode}";
            // 备注
            //"application/x-www-form-urlencoded";
            //MultipartFormDataContent =》multipart / form - data
            //FormUrlEncodedContent =》application / x - www - form - urlencoded
            //StringContent =》application / json等
            //StreamContent =》binary
            var nameValueCollection = new List<KeyValuePair<string, string>>
            {
                new KeyValuePair<string, string>("phone", phoneNumberJoin),
                new KeyValuePair<string, string>("message", msgContentJoin),
                new KeyValuePair<string, string>("acctno", accessKeyId),
                new KeyValuePair<string, string>("password", md5AccessKeySecret),
                new KeyValuePair<string, string>("extno", "")
            };
            // request.Content = new JsonContent(bodyData);
            request.Content = new FormUrlEncodedContent(nameValueCollection);

            var client = HttpClientFactory.CreateClient();
            var response = await client.SendAsync(request);
            var responseContentStr = await response.Content.ReadAsStringAsync();

            var sendResponse = new SendResponse
            {
                RequestId = Guid.NewGuid().ToString()
            };

            if (!response.IsSuccessStatusCode)
            {
                sendResponse.Code = response.StatusCode.ToString();
                sendResponse.Message = responseContentStr;

                var result1 = OperationResult.Error(sendResponse);
                return await Task.Factory.StartNew(() => result1);
            }
            //处理XML返回结果
            try
            {
                XmlDocument xmldoc = new();
                xmldoc.LoadXml(responseContentStr);
                XmlNode xmlNodeReturnSms = xmldoc.SelectSingleNode("returnsms");
                if (xmlNodeReturnSms == null)
                {
                    sendResponse.Code = response.StatusCode.ToString();
                    sendResponse.Message = responseContentStr;

                    var result2 = OperationResult.Error(sendResponse);
                    return await Task.Factory.StartNew(() => result2);
                }
                string returnstatus = xmlNodeReturnSms.SelectSingleNode("returnstatus")?.InnerText;
                string message = xmlNodeReturnSms.SelectSingleNode("message")?.InnerText;
                string taskID = xmlNodeReturnSms.SelectSingleNode("taskID")?.InnerText;

                sendResponse.Code = message;
                sendResponse.Message = returnstatus;
                sendResponse.BizId = taskID;

                if (!sendResponse.Succeeded)
                {
                    var result3 = OperationResult.Error(sendResponse);
                    return await Task.Factory.StartNew(() => result3);
                }

                //查询发送状态
                //为保证服务商数据已持久化可供查询，建议线程睡眠3秒后继续执行下步操作
                Thread.Sleep(3000);
                //设置查询参数
                QueryParamsDto QueryParamsDto = new()
                {
                    PhoneNumber = "",
                    SendDate = DateTime.Now,
                    PageSize = 10,
                    CurrentPage = 1,
                    BizId = sendResponse.BizId,
                };
                var statusResponse = await SmsInquirer.QuerySentStatusAsync(QueryParamsDto);
                if (!statusResponse.Succeeded)
                {
                    var result4 = statusResponse.ToOperationResult(sendResponse);
                    return await Task.Factory.StartNew(() => result4);
                }
                sendResponse.Status.StatusDtos = statusResponse.Data.StatusDtos.FindAll(o => o.BizId == sendResponse.BizId);
                sendResponse.Status.TotalCount = sendResponse.Status.StatusDtos.Count.ToString();

                var result = OperationResult.Success(sendResponse);
                return await Task.Factory.StartNew(() => result);
            }
            catch
            {
                //smsSentResponse.Code = response.StatusCode.ToString();
                //smsSentResponse.Message = responseContentStr;
                sendResponse.Code = "ValidError";
                sendResponse.Message = I18N.T("调用接口返回错误，有可能参数设置不正确！");

                var result = OperationResult.Error(sendResponse);
                return await Task.Factory.StartNew(() => result);
            }
        }
        #endregion

        #endregion

    }
    #endregion

}
